package club.kingyin.easycache.component.annotation.handler;

import club.kingyin.easycache.component.annotation.Ignore;
import club.kingyin.easycache.key.DefaultEasyCacheKey;
import club.kingyin.easycache.cache.AbstractCache;
import club.kingyin.easycache.component.annotation.EasyCache;
import club.kingyin.easycache.component.annotation.Param;
import club.kingyin.easycache.component.annotation.Remove;
import club.kingyin.easycache.exception.ParameterException;
import club.kingyin.easycache.key.EasyCacheKey;
import club.kingyin.easycache.method.CacheMethod;
import club.kingyin.easycache.proxy.ProxyCacheInvokePostProcess;
import club.kingyin.easycache.utils.AnnotationUtils;
import lombok.extern.slf4j.Slf4j;

import static club.kingyin.easycache.utils.AnnotationUtils.createByParams;

/**
 * 这是一个极为重要的组件，是缓存一致性协议的必要存在
 * 其控制着Remove注解的核心功能，使用该注解能够异步删除缓存中的数据
 * 注意：虽然异步删除缓存对目标方法的性能影响很小，但会在查询中存在一定的延迟！
 */
@Slf4j
public class AnnotationRemoveHandler implements ProxyCacheInvokePostProcess {

    // 存在Remove注解时默认不记录缓存，若需要记录则开启EasyCache 的cache开关
    // 存在Ignore注解也默认不记录缓存
    @Override
    public boolean getCacheInterceptor(boolean pre, CacheMethod target,EasyCacheKey key) {
        if (target.getMethod().isAnnotationPresent(EasyCache.class)) {
            if (target.getMethod().getDeclaredAnnotation(EasyCache.class).cache()) {
                return pre;
            }
        }
        if (target.getMethod().isAnnotationPresent(Remove.class)) {
            return false;
        }
        if (target.getMethod().isAnnotationPresent(EasyCache.class)) {
            EasyCache easyCache = target.getMethod().getDeclaredAnnotation(EasyCache.class);
            if (easyCache.removes().length > 0) {
                return false;
            }
        }
        if (target.getMethod().isAnnotationPresent(Ignore.class)) {
            return false;
        }
        return pre;
    }

    @Override
    public void postProcessAfterGetCache(CacheMethod target,AbstractCache cache, Object res, EasyCacheKey key) {
        if (target.getMethod().isAnnotationPresent(EasyCache.class)) {
            EasyCache easyCache = target.getMethod().getDeclaredAnnotation(EasyCache.class);
            for (Remove remove : easyCache.removes()) {
                EasyCacheKey cacheKey = analysisRemove(remove, key);
                cache.deleteCache(cacheKey);
            }
        }
        // 在这里执行删除等一系列操作
        for (Remove remove : target.getMethod().getAnnotationsByType(Remove.class)) {
            // 解析Remove并生成Key
            EasyCacheKey cacheKey = analysisRemove(remove, key);
            // 通过Key删除缓存
            cache.deleteCache(cacheKey);
        }
    }

    public EasyCacheKey analysisRemove(Remove remove, EasyCacheKey key) {
        DefaultEasyCacheKey.Builder builder = new DefaultEasyCacheKey.Builder();
        checkOrAddModuleAndNameToKeyThenException(remove, builder, key);
        Param[] params = remove.prams();
        // 在这里生成KEY

        // 解析Param value优先级大于ref，有name属性则以name为参数名，否则以ref的默认参数名
        return createByParams(params,builder,key, builder.getPrams().keySet());
    }


    private void checkOrAddModuleAndNameToKeyThenException(Remove remove, DefaultEasyCacheKey.Builder builder, EasyCacheKey key) {
        if (AnnotationUtils.PRAM_NULL.equals(remove.methodName())) {
            throw new ParameterException("方法名不能为空 " + key);
        } else {
            builder.setMethodName(remove.methodName());
        }
        builder.setModule(remove.module());
    }


    private boolean checkRename(String sources) {
        int index = sources.indexOf('=');
        return index > 0 && index < sources.length()-1;
    }
}
